package cw.spring.security.acl.pof.test;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;

import javax.sql.DataSource;

import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.datatype.DataType;
import org.dbunit.dataset.datatype.DataTypeException;
import org.dbunit.dataset.datatype.DefaultDataTypeFactory;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.ClassPathResource;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.test.AbstractTransactionalDataSourceSpringContextTests;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

import cw.spring.security.acl.poc.services.IAuthenticationService;

@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring-core-main.xml" })
public abstract class AbstractTestModeLauncher extends AbstractTransactionalDataSourceSpringContextTests implements ApplicationContextAware {

  //-------------------------------------------------------------------------------------------//
  // Variables Declaration                                                                     //
  //-------------------------------------------------------------------------------------------//

  protected static String[] contextFiles = new String[] { "spring-core-main.xml" };

  protected static ApplicationContext ctx = null;

  public static ApplicationContext getCtx() {
    return ctx;
  }

  public static void setCtx(ApplicationContext ctx) {
    AbstractTestModeLauncher.ctx = ctx;
  }

  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    if (ctx == null) {
      ctx = applicationContext;
      this.transactionManager = (HibernateTransactionManager) ctx.getBean("transactionManager");
    }
    this.transactionManager = (HibernateTransactionManager) ctx.getBean("transactionManager");
  }

  protected IDatabaseConnection dbConnection;

  //-------------------------------------------------------------------------------------------//
  // Types Declaration                                                                         //
  //-------------------------------------------------------------------------------------------//

  public class HsqlDataTypeFactory extends DefaultDataTypeFactory {

    public DataType createDataType(int sqlType, String sqlTypeName) throws DataTypeException {
      if (sqlType == Types.BOOLEAN) {
        return DataType.BOOLEAN;
      }

      return super.createDataType(sqlType, sqlTypeName);
    }
  }

  //-------------------------------------------------------------------------------------------//
  // Methods Declaration                                                                       //
  //-------------------------------------------------------------------------------------------//

  @BeforeClass
  public static void logBeginning() {
    System.out.println("Starting unitary tests");
  }
  
  boolean initialized = false;

  @Before
  public void initEnvironment() {
    if(!initialized){
      System.out.println("Initializing spring");
      initSpring();
      System.out.println("Initializing database");
      initDB();
      System.out.println("Authenticating");
      initialized = true;
      //authenticate();
    }
  }

  protected void authenticate() {
    IAuthenticationService authenticateService = (IAuthenticationService) ctx.getBean("authenticationService");
    // authenticateService.authenticate("user1", ""); // Thiriet
    authenticateService.authenticate("user1", "");
  }

  protected void initSpring() {

    try {
      // Load Spring context for tests

      DataSource dataSource = (DataSource) ctx.getBean("dataSource");

      Connection conn = dataSource.getConnection();
      dbConnection = new DatabaseConnection(conn);
      DatabaseConfig config = dbConnection.getConfig();
      config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new HsqlDataTypeFactory());

    } catch (BeansException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (DatabaseUnitException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (SQLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

  }

  private void initDB() {

    try {
      ClassPathResource file = (ClassPathResource) ctx.getResource("./hsqldb/dbCreate.xml");
      FileReader rd = new FileReader(file.getFile());
      char[] buf = new char[(int) file.getFile().length()];
      rd.read(buf);
      String dbString = new String(buf);

      IDataSet data = new FlatXmlDataSet(new StringReader(dbString));
      DatabaseOperation.INSERT.execute(dbConnection, data);
    } catch (BeansException e) {
      e.printStackTrace();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (DataSetException e) {
      e.printStackTrace();
    } catch (SQLException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (DatabaseUnitException e) {
      e.printStackTrace();
    }

  }

//  @After
//  public void destroyDbConnection() {
//    dbConnection.getSchema();
//    if (dbConnection != null) {
//
//      ClassPathResource file = (ClassPathResource) ctx.getResource("hsqldb/dbDestroy.xml");
//      try {
//        IDataSet data = new FlatXmlDataSet(file.getFile());
//        DatabaseOperation.DELETE_ALL.execute(dbConnection, data);
//      } catch (DataSetException e) {
//        e.printStackTrace();
//      } catch (IOException e) {
//        e.printStackTrace();
//      } catch (DatabaseUnitException e) {
//        e.printStackTrace();
//      } catch (SQLException e) {
//        e.printStackTrace();
//      }
//
//      if (dbConnection != null) {
//        try {
//          dbConnection.close();
//        } catch (SQLException e) {
//          e.printStackTrace();
//        }
//      }
//
//    }
//  }

}
